<?php
/**
 * --------------------------------------------------------------------
 * MCore框架
 * 作者：阿枫，QQ：52037872，Email：nczy520@gmail.com
 * --------------------------------------------------------------------
 *
 * SVN revision information:
 * @version $Revision: 50 $:
 * @author  $Author: zy $:
 * @date      $Date: 2013-11-09 19:34:15 +0800 (星期六, 09 十一月 2013) $:
 * @url         $HeadURL: svn://vps.mdeve.com/web_mcore/manage/function/global.func.php $:
 */

class _TamperproofClass extends __basic_def {

    function _main() {
        global $_M;

        $randstr = create_random_str(32);
        $_SESSION["tamperproof_verify_code"] = $randstr;

        $_M->db();
        $row = $_M->db->get_row(array("table"=>"tamperproof", "field"=>"count(*) as num"));
        $total_files = $row["num"];

        $tamperproof_enable = 0;
        $row = $_M->db->get_row(array("table"=>"options", "field"=>"options_value", "where"=>"type='user' and options_name='tamperproof_enable' and category='tools'"));
        if(is_array($row)) {
            $tamperproof_enable = $row["options_value"] ?? 0;
        }

        $exclude = "";
        $row = $_M->db->get_row(array("table"=>"options", "field"=>"options_value", "where"=>"type='user' and options_name='tamperproof_exclude' and category='tools'"));
        if(is_array($row)) {
            $exclude = $row["options_value"] ?? "";
        }


        $breadcrumb = array(
            "系统工具" => "#",
            "文件防篡改" => "",
        );

        $_M->template();
        $_M->template->load(MANAGE_PATH. "/templates/tools/tamperproof");
        $_M->template->set_var("{tamperproof_verify_code}", $randstr);
        $_M->template->set_var("{total_files}", $total_files);
        $_M->template->set_var("{enable}", $tamperproof_enable);
        $_M->template->set_var("{exclude}", $exclude);
        $_M->template->insert_html(_generate_breadcrumb($breadcrumb));
        $_M->template->display();
    }

    function option_onoff(){
        global $_M;

        $state = intval(filter_input(INPUT_POST, "state"));

        $_M->db();
        $data = array(
            "type" => "user",
            "options_name" => "tamperproof_enable",
            "options_value" => $state,
            "info" => "文件防篡改开关",
            "category" => "tools",
            "field" => "boolean",
        );
        $_M->db->replace($data, array("table"=>"options", "where"=>"type='user' and options_name='tamperproof_enable' and category='tools'"));
        ajax_result("successful");
    }

    /* 扫描本地文件 */
    function scan_local_files(){
        global $_M;

        $code = filter_input(INPUT_POST, "code");
        if($code != $_SESSION["tamperproof_verify_code"]) ajax_result("error", "验证错误！");

        $_M->db();
        $exclude = "";
        $row = $_M->db->get_row(array("table"=>"options", "field"=>"options_value", "where"=>"type='user' and options_name='tamperproof_exclude' and category='tools'"));
        if(is_array($row)) {
            $exclude = $row["options_value"] ?? "";
        }
        $exclude_array = array();
        if(strlen($exclude)) {
            $exclude = str_replace("\r", "", $exclude);
            $exclude_array = explode("\n", $exclude);
        }

        $_M->file();
        $files = $_M->file->seek_file(".*", ".", 1, 50, 99999);
        $result = array();
        foreach($files as $file) {
            $file["location"] = str_replace($_M->cfg["INSTALL_PATH"]. "/", "", $file["location"]);
            $excluded = false;
            if(sizeof($exclude_array)) {
                foreach($exclude_array as $e) {
                    $e = trim($e);
                    $s = substr($file["location"], 0, strlen($e));
                    if($e == $s) {
                        $excluded = true;
                        break;
                    }
                }
            }
            if($excluded) continue;
            $result[] = $file["location"];
        }

        ajax_result("successful", $result);
    }

    /* 保护指定文件 */
    function protect_local_file(){
        global $_M;

        $location = clear_string(filter_input(INPUT_POST, "location"));
        $code = filter_input(INPUT_POST, "code");
        if($code != $_SESSION["tamperproof_verify_code"]) ajax_result("error", "验证错误！");

        if(!file_exists($location)) ajax_result("error", "文件：{$location} 没有找到，保护失败！");
        $md5 = md5_file($location);
        $sha1 = sha1_file($location);
        $content = file_get_contents($location);

        $_M->db();
        $row = $_M->db->get_row(array("table"=>"tamperproof", "where"=>"location='{$location}'"));
        if(is_array($row)) {
            if($row["md5"] == $md5 && $row["sha1"] == $sha1) {
                // 相同，不用更新
                ajax_result("successful");
            }
        }

        $data = array(
            "location" => $location,
            "md5" => $md5,
            "sha1" => $sha1,
            "sizes" => filesize($location),
            "filedata" => $_M->encrypt->EncodeZ($content),
            "last_uid" => $_M->userinfo["id"]
        );
        if(false === $row) {
            $_M->db->insert($data, array("table"=>"tamperproof"));
        } else {
            $_M->db->update($data, array("table"=>"tamperproof", "where"=>"location='{$location}'"));
        }

        ajax_result("successful");
    }

    /* 扫描保护的文件 */
    function scan_protected_files(){
        global $_M;

        ini_set("memory_limit","512M");

        $code = filter_input(INPUT_POST, "code");
        if($code != $_SESSION["tamperproof_verify_code"]) ajax_result("error", "验证错误！");

        $_M->db();
        $_M->file();

        $exclude = "";
        $row = $_M->db->get_row(array("table"=>"options", "field"=>"options_value", "where"=>"type='user' and options_name='tamperproof_exclude' and category='tools'"));
        if(is_array($row)) {
            $exclude = $row["options_value"] ?? "";
        }
        $exclude_array = array();
        if(strlen($exclude)) {
            $exclude = str_replace("\r", "", $exclude);
            $exclude_array = explode("\n", $exclude);
        }

        $files = $_M->file->seek_file(".*", ".", 1, 50, 99999);
        $result = array();
        foreach($files as $file) {
            $file["location"] = str_replace($_M->cfg["INSTALL_PATH"]. "/", "", $file["location"]);
            $excluded = false;
            if(sizeof($exclude_array)) {
                foreach($exclude_array as $e) {
                    $e = trim($e);
                    $s = substr($file["location"], 0, strlen($e));
                    if($e == $s) {
                        $excluded = true;
                        break;
                    }
                }
            }
            if($excluded) continue;
            $result[] = $file["location"];
        }


        $row = $_M->db->get_rows(array("table"=>"tamperproof", "field"=>"location,md5,sha1"));
        $contrast = array();
        // 对比1，本地文件对比数据库
        foreach ($result as $file) {
            // 读取文件md5和sha1值，并和数据库对比，返回结果
            $location = str_replace($_M->cfg["INSTALL_PATH"]. "/", "", $file);
            $md5 = md5_file($location);
            $sha1 = sha1_file($location);
            $sizes = filesize($location);
            $find = false;
            $changed = false;
            foreach ($row as $r) {
                if($r["location"] == $location) {
                    $find = true;
                    if($md5 != $r["md5"] || $sha1 != $r["sha1"]) $changed = true;
                    break;
                }
            }
            $contrast[] = array(
                "location" => $location,
                "sizes" => byte_format($sizes),
                "find" => $find ? "-" : "<span class='text-primary'>新增</span>",
                "changed" => $changed ? "<span class='text-danger'>已修改</span>" : "-",
            );
        }
        // 对比2，数据库对比文件
        foreach($row as $r) {
            // 第一步，如果对比中存在此文件，则跳过
            $find = false;
            foreach($contrast as $c) {
                if($c["location"] == $r["location"]) {
                    $find = true;
                    break;
                }
            }
            if($find) continue;
            // 第二步，对比本地文件
            $find = false;
            foreach ($result as $file) {
                if($file == $r["location"]) {
                    $find = true;
                    break;
                }
            }
            if(!$find) {
                $contrast[] = array(
                    "location" => $r["location"],
                    "sizes" => "-",
                    "find" => $find ? "-" : "<span class='text-danger'>已删除</span>",
                    "changed" => "-",
                );
            }
        }

        $_M->template();
        $_M->template->load(MANAGE_PATH. "/templates/tools/tamperproof_file_list");
        $_M->template->process_block("list", $contrast);
        $result = $_M->template->display(true);

        ajax_result("successful", $result);
    }


    // 排除文件或目录
    function _protect_exclude_files(){
        global $_M;

        $code = filter_input(INPUT_POST, "code");
        if($code != $_SESSION["tamperproof_verify_code"]) ajax_result("error", "验证错误！");

        $exclude = clear_string(filter_input(INPUT_POST, "exclude"));

        $_M->db();
        $data = array(
            "type" => "user",
            "options_name" => "tamperproof_exclude",
            "options_value" => $exclude,
            "info" => "文件防篡改 > 排除的目录或文件",
            "category" => "tools",
            "field" => "textarea",
        );
        $_M->db->replace($data, array("table"=>"options", "where"=>"type='user' and options_name='tamperproof_exclude' and category='tools'"));
        ajax_result("successful", "设置排除目录和文件完成");
    }

    // 显示文件修改历史
    function _protect_history(){
        global $_M;

        $code = filter_input(INPUT_POST, "code");
        if($code != $_SESSION["tamperproof_verify_code"]) ajax_result("error", "验证错误！");

        $location = clear_string(filter_input(INPUT_POST, "location"));
        if(!strlen($location)) ajax_result("error", "文件没有找到！");

        $_M->db();
        $row = $_M->db->get_rows(array("table"=>"tamperproof_history", "field"=>"id,operation,sizes,createtime", "where"=>"location='{$location}'", "order"=>"createtime desc"));
        for($i=0; $i<sizeof($row); $i++) {
            $row[$i]["sizes"] = byte_format($row[$i]["sizes"]);
        }

        $_M->template();
        $_M->template->load(MANAGE_PATH. "/templates/tools/tamperproof_history");
        $_M->template->process_block("list", $row);
        $result = $_M->template->display(true);

        ajax_result("successful", $result);
    }

    // 从历史中恢复文件
    function _protect_restore_file(){
        global $_M;

        $code = filter_input(INPUT_POST, "code");
        if($code != $_SESSION["tamperproof_verify_code"]) ajax_result("error", "验证错误！");

        $id = intval(filter_input(INPUT_POST, "id"));
        if(!$id) ajax_result("error", "失败：没有找到要恢复的文件！");

        $_M->db();
        $row = $_M->db->get_row(array("table"=>"tamperproof_history", "where"=>"id={$id}"));
        if(false === $row) ajax_result("error", "失败：没有找到要恢复的文件！！");
        if(!is_writable($row["location"])) ajax_result("error", "失败：文件没有写入权限！");

        $content = $_M->encrypt->DecodeZ($row["filedata"]);
        file_put_contents($row["location"], $content);

        ajax_result("successful", "恢复成功！");

    }

}